#ifndef MESH_H
#define MESH_H

#include <vector>
#include "vectors.h"
#include "hash.h"
#include "boundingbox.h"
#include "argparser.h"
#include<utility>

class Vertex;
class Edge;
class Triangle;

using namespace std;
// ======================================================================
// ======================================================================

class ClothParticle {
public:
  // ACCESSORS
  const Vec3f& getOriginalPosition() const{ return original_position; }
  const Vec3f& getPosition() const{ return position; }
  const Vec3f& getVelocity() const{ return velocity; }
  const Vec3f& getAcceleration() const { return acceleration; }
  Vec3f getForce() const { return mass*acceleration; }
  float getMass() const { return mass; }
  bool isFixed() const { return fixed; }
  // MODIFIERS
  void setOriginalPosition(const Vec3f &p) { original_position = p; }
  void setPosition(const Vec3f &p) { position = p; }
  void setVelocity(const Vec3f &v) { velocity = v; }
  void setAcceleration(const Vec3f &a) { acceleration = a; }
  void setMass(float m) { mass = m; }
  void setFixed(bool b) { fixed = b; }
  
  vector<pair<int,int> > struc;
  vector<pair<int, int> > shear;
  vector<pair<int, int> > bend;
  vector<Vec3f*> normals;
  
  bool cut;
  BoundingBox box;
  bool cut2;
  Vec3f lastSpot;
private:
  // REPRESENTATION
  Vec3f original_position;
  Vec3f position;
  Vec3f velocity;
  Vec3f acceleration;
  float mass;
  bool fixed;
};


class Mesh {

public:

  // ========================
  // CONSTRUCTOR & DESTRUCTOR
  Mesh(ArgParser *args);
  ~Mesh();
  void Load(const char *input_file);
  void Animate();
  void Paint2();
    
  // ========
  // VERTICES
  int numVertices() const { return vertices.size(); }
  Vertex* addVertex(const Vec3f &pos);
  // look up vertex by index from original .obj file
  Vertex* getVertex(int i) const {
    assert (i >= 0 && i < numVertices());
    Vertex *v = vertices[i];
    assert (v != NULL);
    return v; }
	
  //void removeVertex(

  // ==================================================
  // PARENT VERTEX RELATIONSHIPS (used for subdivision)
  // this creates a relationship between 3 vertices (2 parents, 1 child)
  void setParentsChild(Vertex *p1, Vertex *p2, Vertex *child);
  // this accessor will find a child vertex (if it exists) when given
  // two parent vertices
  Vertex* getChildVertex(Vertex *p1, Vertex *p2) const;

  // =====
  // EDGES
  int numEdges() const { return edges.size(); }
  // this efficiently looks for an edge with the given vertices, using a hash table
  Edge* getMeshEdge(Vertex *a, Vertex *b) const;

  // =========
  // TRIANGLES
  int numTriangles() const { return triangles.size()-num_d; }
  Triangle* addTriangle(Vertex *a, Vertex *b, Vertex *c);
  void removeTriangle(Triangle *t);

  // ===============
  // OTHER ACCESSORS
  const BoundingBox& getBoundingBox() const { return bbox; }
  
  // ===============
  // OTHER FUNCTIONS
  void Paint(ArgParser *args);
  void LoopSubdivision();
  void Simplification(int target_tri_count);
  int num_d;
  
  ClothParticle *particles;
  int size;
  
  // HELPER FUNCTION
  void computeBoundingBox();

  // REPRESENTATION
  ArgParser *args;
  // grid data structure
  int nx, ny;
  
  BoundingBox box;
  // simulation parameters
  float damping;
  // spring constants
  float k_structural;
  float k_shear;
  float k_bend;
  // correction thresholds
  float provot_structural_correction;
  float provot_shear_correction;
  
  // (NOT SO) PRIVATE ACCESSORS
  const ClothParticle& getParticle(int i, int j) const {
    assert (i >= 0 && i < nx && j >= 0 && j < ny);
    return particles[i + j*nx]; }
  ClothParticle& getParticle(int i, int j) {
    assert (i >= 0 && i < nx && j >= 0 && j < ny);
    return particles[i + j*nx]; }

private:

  // ==============
  // REPRESENTATION
  std::vector<Vertex*> vertices;
  edgeshashtype edges;
  triangleshashtype triangles;
  BoundingBox bbox;
  vphashtype vertex_parents;
  

};

// ======================================================================
// ======================================================================

#endif




